package handler

import (
	"context"
	"portal_rpc/global"
	"portal_rpc/model"
	pb "portal_rpc/proto"
	"portal_rpc/util"

	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type PortalServer struct {
	pb.UnimplementedPortalRecordServer
}

func (s *PortalServer) CreatePortalDevice(ctx context.Context, req *pb.CreatePortalDeviceRequest) (*pb.CreatePortalDeviceResponse, error) {
	device := model.PortalDevice{
		PortalCode: req.PortalCode,
		MacAddress: req.MacAddress,
	}
	result := global.DB.Save(&device)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "create portal device failed with database")
	}
	return &pb.CreatePortalDeviceResponse{
		Id: int32(device.ID),
	}, nil
}

func (s *PortalServer) GetPortalDeviceByMacAddress(ctx context.Context, req *pb.GetPortalDeviceByMacAddressRequest) (*pb.GetPortalDeviceResponse, error) {
	var device model.PortalDevice
	result := global.DB.Model(&model.PortalDevice{}).Where("mac_address = ?", req.MacAddress).First(&device)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "get portal device failed with mac address")
	}
	return &pb.GetPortalDeviceResponse{
		Id:         int32(device.ID),
		PortalCode: device.PortalCode,
		MacAddress: device.MacAddress,
	}, nil
}

func (s *PortalServer) GetPortalDeviceByPortalCode(ctx context.Context, req *pb.GetPortalDeviceByPortalCodeRequest) (*pb.GetPortalDeviceResponse, error) {

	var device model.PortalDevice
	result := global.DB.Model(&model.PortalDevice{}).Where("portal_code = ?", req.PortalCode).First(&device)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "get portal device failed with portal code")
	}
	return &pb.GetPortalDeviceResponse{
		Id:         int32(device.ID),
		PortalCode: device.PortalCode,
		MacAddress: device.MacAddress,
	}, nil
}

func (s *PortalServer) CreatePortalRecord(ctx context.Context, req *pb.CreatePortalRecordRequest) (*pb.CreatePortalRecordResponse, error) {

	// 生成存证哈希
	hashText, err := util.GeneratePortalRecordEnvidence(&util.PortalData{
		PortalCode:               req.PortalCode,
		SnapTime:                 req.SnapTime,
		LicensePlateNumber:       req.LicensePlateNumber,
		LicensePlateNumber2:      req.LicensePlateNumber2,
		LicensePlateColor:        req.LicensePlateColor,
		LicensePlateColor2:       req.LicensePlateColor2,
		VehicleColor:             req.VehicleColor,
		VehicleModel:             req.VehicleModel,
		LaneNumber:               req.LaneNumber,
		SnapNumber:               req.SnapNumber,
		DangerousChemicalsSymols: req.DangerousChemicalsSymols,
		DangerousChemicalsType:   req.DangerousChemicalsType,
		AxleType:                 req.AxleType,
		AxleNumber:               req.AxleNumber,
		WheelNumber:              req.WheelNumber,
		VehicleSpeed:             req.VehicleSpeed,
		VehicleLength:            req.VehicleLength,
		TrafficVehicleModel:      req.TrafficVehicleModel,
		ImgExist:                 req.ImgExist,
		BeforeCompress:           req.BeforeCompress,
		AfterCompress:            req.AfterCompress,
		VehicleWidth:             req.VehicleWidth,
		VehicleHeight:            req.VehicleHeight,
		ImageType:                req.ImageType,
		ImageUrl:                 req.ImageUrl,
		RecordId:                 req.RecordId,
		ProvinceCode:             req.ProvinceCode,
		BelongVideoUrl:           req.BelongVideoUrl,
		BelongVideoStartTime:     req.BelongVideoStartTime,
		BelongVideoEndTime:       req.BelongVideoEndTime,
	})
	if err != nil {
		zap.L().Error("生成存证哈希错误", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "generate trade record envidence failed")
	}
	// 避免哈希碰撞，这里的存证哈希，存储为ProvinceCode:RecordId:HashText
	hashText = req.ProvinceCode + ":" + req.RecordId + ":" + hashText

	// 存储数据到合约

	tx, receipt, err := global.PortalManager.CreatePortalProve(global.Client.GetTransactOpts(), req.ProvinceCode, req.RecordId, req.SnapTime, hashText)
	if err != nil {
		zap.L().Error("数据上链失败",
			zap.Error(err),
			zap.Any("record",
				req),
		)
		return nil, status.Errorf(codes.Internal, "create portal record prove failed with contract")
	}

	zap.L().Debug("交易的状态", zap.Int("status", receipt.Status))

	record := model.PortalRecord{
		PortalCode:               req.PortalCode,
		SnapTime:                 req.SnapTime,
		LicensePlateNumber:       req.LicensePlateNumber,
		LicensePlateNumber2:      req.LicensePlateNumber2,
		LicensePlateColor:        req.LicensePlateColor,
		LicensePlateColor2:       req.LicensePlateColor2,
		VehicleColor:             req.VehicleColor,
		VehicleModel:             req.VehicleModel,
		LaneNumber:               req.LaneNumber,
		SnapNumber:               req.SnapNumber,
		DangerousChemicalsSymols: req.DangerousChemicalsSymols,
		DangerousChemicalsType:   req.DangerousChemicalsType,
		AxleType:                 req.AxleType,
		AxleNumber:               req.AxleNumber,
		WheelNumber:              req.WheelNumber,
		VehicleSpeed:             req.VehicleSpeed,
		VehicleLength:            req.VehicleLength,
		TrafficVehicleModel:      req.TrafficVehicleModel,
		ImgExist:                 req.ImgExist,
		BeforeCompress:           req.BeforeCompress,
		AfterCompress:            req.AfterCompress,
		VehicleWidth:             req.VehicleWidth,
		VehicleHeight:            req.VehicleHeight,
		ImageType:                req.ImageType,
		ImageUrl:                 req.ImageUrl,
		RecordId:                 req.RecordId,
		BlockChainHashCode:       tx.Hash().Hex(),
		RecordHashCode:           hashText,
		ProvinceCode:             req.ProvinceCode,
		BelongVideoUrl:           req.BelongVideoUrl,
		BelongVideoStartTime:     req.BelongVideoStartTime,
		BelongVideoEndTime:       req.BelongVideoEndTime,
		Status:                   0,
	}

	result := global.DB.Save(&record)

	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "create portal record failed with database")
	}
	return &pb.CreatePortalRecordResponse{
		Id:       int32(record.ID),
		HashText: hashText,
		TxHash:   tx.Hash().Hex(),
	}, nil
}

func (s *PortalServer) GetPortalRecord(ctx context.Context, req *pb.GetPortalRecordRequest) (*pb.GetPortalRecordResponse, error) {

	var record model.PortalRecord
	result := global.DB.Model(&model.PortalRecord{}).Where("province_code = ? AND record_id = ?", req.ProvinceCode, req.RecordId).First(&record)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, "get portal record failed")
	}
	return &pb.GetPortalRecordResponse{
		PortalCode:               record.PortalCode,
		SnapTime:                 record.SnapTime,
		LicensePlateNumber:       record.LicensePlateNumber,
		LicensePlateNumber2:      record.LicensePlateNumber2,
		LicensePlateColor:        record.LicensePlateColor,
		LicensePlateColor2:       record.LicensePlateColor2,
		VehicleColor:             record.VehicleColor,
		VehicleModel:             record.VehicleModel,
		LaneNumber:               record.LaneNumber,
		SnapNumber:               record.SnapNumber,
		DangerousChemicalsSymols: record.DangerousChemicalsSymols,
		DangerousChemicalsType:   record.DangerousChemicalsType,
		AxleType:                 record.AxleType,
		AxleNumber:               record.AxleNumber,
		WheelNumber:              record.WheelNumber,
		VehicleSpeed:             record.VehicleSpeed,
		VehicleLength:            record.VehicleLength,
		TrafficVehicleModel:      record.TrafficVehicleModel,
		ImgExist:                 record.ImgExist,
		BeforeCompress:           record.BeforeCompress,
		AfterCompress:            record.AfterCompress,
		VehicleWidth:             record.VehicleWidth,
		VehicleHeight:            record.VehicleHeight,
		ImageType:                record.ImageType,
		ImageUrl:                 record.ImageUrl,
		RecordId:                 record.RecordId,
		BlockChainHashCode:       record.BlockChainHashCode,
		RecordHashCode:           record.RecordHashCode,
		ProvinceCode:             record.ProvinceCode,
		BelongVideoUrl:           record.BelongVideoUrl,
		BelongVideoStartTime:     record.BelongVideoStartTime,
		BelongVideoEndTime:       record.BelongVideoEndTime,
		Status:                   uint32(record.Status),
	}, nil

}
